package bsc.war.service;

import bsc.ejb.entity.ActionPlan;
import bsc.ejb.entity.ActionPlanPerson;
import bsc.ejb.entity.Attachment;
import bsc.ejb.entity.ColorimetrySettings;
import bsc.ejb.entity.Comparator;
import bsc.ejb.entity.ComparatorDimensionalCut;
import bsc.ejb.entity.Dimension;
import bsc.ejb.entity.DimensionMember;
import bsc.ejb.entity.DimensionalCut;
import bsc.ejb.entity.DimensionalCutMember;
import bsc.ejb.entity.Label;
import bsc.ejb.entity.MapDrawingSettings;
import bsc.ejb.entity.Milestone;
import bsc.ejb.entity.MilestoneTracer;
import bsc.ejb.entity.Note;
import bsc.ejb.entity.Person;
import bsc.ejb.entity.PersonScoreCard;
import org.apache.commons.io.FileUtils;
import bsc.ejb.entity.Pointer;
import bsc.ejb.entity.Project;
import bsc.ejb.entity.SRMTopic;
import bsc.ejb.entity.ScoreCard;
import bsc.ejb.entity.ScoreCardDimension;
import bsc.ejb.entity.ScoreCardRelation;
import bsc.ejb.entity.ScoreView;
import bsc.ejb.entity.Settings;
import bsc.ejb.entity.Task;
import bsc.ejb.entity.Topic;
import bsc.ejb.entity.TopicScoreView;
import bsc.ejb.entity.Tracer;
import bsc.ejb.metadata.Colorimetry;
import bsc.ejb.metadata.Comparation;
import bsc.ejb.metadata.MapDrawing;
import bsc.war.ajax.DeleteNote;
import bsc.war.delegate.DelegateBSC;
import bsc.war.factory.Factory;
import bsc.war.model.ActionPlanPojo;
import bsc.war.model.DatesPojo;
import bsc.war.model.Score;
import bsc.war.model.TracerPojo;
import com.towel.math.Expression;
import java.io.File;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TimeZone;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.collections.ListUtils;
import org.apache.log4j.Logger;

/**
 *
 * @author memozac
 */
public class ScoreCardUtils {

    private static Logger logger = Logger.getLogger(ScoreCardUtils.class);
    private static final String VARIABLE_CONS = "C";
    private static final String VARIABLE_PIVOT = "P";
    private static final String VARIABLE_EXP = "(" + VARIABLE_CONS + "[0-9]+)";

    public static String topicStatus(TopicScoreView.Type type) {
        switch (type) {
            case DELAYED:
                return "Con Retraso";
            case IN_PROCESS:
                return "En proceso";
            case COMPLETED:
                return "Completado";
        }
        return null;
    }

    public static DatesPojo generateRangeDates(DelegateBSC delegate, Comparation comparation, ScoreCard scoreCard, Date date) {
        DatesPojo datesPojo = new DatesPojo();
        Date lastDate = null;
        Date firstDate = null;
        //Generate periods using frecuency
        int jump = 1;
        switch (scoreCard.getSettings().getFrecuency()) {
            case MONTHLY:
                jump = 1;
                break;
            case BIMONTHLY:
                jump = 2;
                break;
            case QUARTERLY:
                jump = 3;
                break;
            case SEMIANNUAL:
                jump = 6;
                break;
            case ANNUAL:
                jump = 12;
                break;

        }

        switch (scoreCard.getSettings().getTemporality()) {
            case LAST:
                //System.out.println("Entre a este caso LAST");
                //Calculate the last date
                Calendar calendarLast = Calendar.getInstance();
                calendarLast.setTime(date);

                int monthLast = calendarLast.get(Calendar.MONTH) + 1;
                int mod = monthLast % jump;
                monthLast = (monthLast - mod);

                Date dateG = generateDate(1, monthLast, calendarLast.get(Calendar.YEAR));

                lastDate = getMaximumDate(dateG);

                //Calculate the First Date
                firstDate = getMinimumDate(dateG);

                break;

            case X_YEARLY:
                lastDate = date;
                firstDate = getMinimumDateMonth(0);
                break;
        }

        datesPojo.setLastDate(lastDate);
        datesPojo.setFirstDate(firstDate);

        return datesPojo;
    }

    public static List<ScoreCard> getSuggestedTopics(DelegateBSC delegate, Comparation comparation, ScoreView scoreView, Date date) {
        return ScoreCardUtils.getBadPointers(delegate, comparation, scoreView.getScoreCard(), date);
    }

    public static List<ScoreCard> getBadPointers(DelegateBSC delegate, Comparation comparation, ScoreCard scoreCard, Date date) {
        List<ScoreCard> scoreChildren = delegate.findScoreCard(scoreCard);// children scorecards

        //SE revisa q no sea Dimensionalcut
        DimensionalCut dimensionalCutScoreCard = null;
        if (scoreCard instanceof DimensionalCut) {
            dimensionalCutScoreCard = (DimensionalCut) scoreCard;
            scoreCard = dimensionalCutScoreCard.getPointer();
        }

        //if (scoreChildren.isEmpty() && scoreCard instanceof Pointer) {
        if (scoreCard instanceof Pointer) {
            DatesPojo datesPojo = generateRangeDates(delegate, comparation, scoreCard, date);
            //Score score = ScoreCardUtils.calculatePointerScore(delegate, comparation, (Pointer) scoreCard, datesPojo.getFirstDate(), datesPojo.getLastDate());// calculates score depending the settings table
            Score score= ScoreCardUtils.calculatePointerScore(delegate, comparation, (Pointer) scoreCard, datesPojo.getFirstDate(), datesPojo.getLastDate(), dimensionalCutScoreCard);
            Colorimetry colorimetry = delegate.findColorimetry(scoreCard, score.getScore());
            List<ScoreCard> addedPointer = new ArrayList<ScoreCard>();
            if (colorimetry != null && colorimetry.getPriority() > 1) {
                //addedPointer.add((DimensionalCut) scoreCard);
                addedPointer.add((DimensionalCut) dimensionalCutScoreCard);
            }
            return addedPointer;
        } else if (scoreChildren.isEmpty() && scoreCard instanceof Project) {
            Score score = ScoreCardUtils.calculateScore(delegate, (Project) scoreCard);
            Colorimetry colorimetry = delegate.findColorimetry(scoreCard, score.getScore());
            List<ScoreCard> addedPointer = new ArrayList<ScoreCard>();
            if (colorimetry != null && colorimetry.getPriority() > 1) {
                addedPointer.add((Project) scoreCard);
            }
            return addedPointer;
        }
        if (scoreCard instanceof Project) {
            Double score = ScoreCardUtils.calculateScore(delegate, comparation, scoreCard, date).getScore();
            Colorimetry colorimetry = delegate.findColorimetry(scoreCard, score);
            List<ScoreCard> addedPointer = new ArrayList<ScoreCard>();
            if (colorimetry != null && colorimetry.getPriority() > 1) {
                addedPointer.add((Project) scoreCard);
            }
            return addedPointer;
        } else {
            List<ScoreCard> addedPointers = new ArrayList<ScoreCard>();
            for (ScoreCard scoreChild : scoreChildren) {
                List<ScoreCard> addedPointer = ScoreCardUtils.getBadPointers(delegate, comparation, scoreChild, date);
                if (!addedPointer.isEmpty()) {
                    addedPointers.addAll(addedPointer);
                }
            }
            return addedPointers;
        }
    }

    public static Double getPercentFactor(DelegateBSC delegate, ScoreCard scoreCard, ScoreCard scoreChild) {
        ScoreCardRelation scoreCardRelation = delegate.findScoreCardRelation(scoreCard.getIdScoreCard(), scoreChild.getIdScoreCard());
        return scoreCardRelation == null ? 0 : scoreCardRelation.getPercentFactor();
    }

    public static Score calculateScore(DelegateBSC delegate, Comparation comparation, ScoreCard scoreCard, Date date) {
        return ScoreCardUtils.calculateScore(delegate, comparation, scoreCard, date, null);
    }

    public static Score calculateScore(DelegateBSC delegate, Comparation comparation, ScoreCard scoreCard, Date date, DimensionalCut dimensionalCut) {
        List<ScoreCard> scoreChildren = delegate.findScoreCard(scoreCard);// children scorecards

        //SE revisa q no sea Dimensionalcut
        DimensionalCut dimensionalCutScoreCard = null;
        if (scoreCard instanceof DimensionalCut) {
            dimensionalCutScoreCard = (DimensionalCut) scoreCard;
            scoreCard = dimensionalCutScoreCard.getPointer();
        }

        //if (scoreChildren.isEmpty() && scoreCard instanceof Pointer) {
        if (scoreCard instanceof Pointer) {
            DatesPojo datesPojo = generateRangeDates(delegate, comparation, scoreCard, date);
            //System.out.println("El DimensionalCut ID es: " + dimensionalCut.getIdDimensionalCut());
            return ScoreCardUtils.calculatePointerScore(delegate, comparation, (Pointer) scoreCard, datesPojo.getFirstDate(), datesPojo.getLastDate(), dimensionalCut);// calculates score depending the settings table
        } else if (scoreChildren.isEmpty() && scoreCard instanceof Project) {
            return ScoreCardUtils.calculateScore(delegate, (Project) scoreCard);
        } else {
            Score score = (Score) Factory.getBean("Score");
            Double _score = 0.0D;
            if (scoreCard instanceof Project) {
                Score projectScore = ScoreCardUtils.calculateScore(delegate, (Project) scoreCard);
                if (projectScore.isOutOfDate()) {
                    score.setOutOfDate(true);
                }
                _score = projectScore.getScore();
            }
            for (ScoreCard scoreChild : scoreChildren) {
                // percent factor determines how much this score weights in relation to his brothers' score
                Score childScore = calculateScore(delegate, comparation, scoreChild, date, dimensionalCut);
                if (childScore.isOutOfDate()) {
                    score.setOutOfDate(true);
                }
                ScoreCardRelation scoreCardRelation = delegate.findScoreCardRelation(scoreCard.getIdScoreCard(), scoreChild.getIdScoreCard());
                _score += childScore.getScore() * scoreCardRelation.getPercentFactor();
            }
            score.setScore(_score);

            return score;
        }
    }

    public static Score calculatePointerScore(DelegateBSC delegate, Comparation comparation, Pointer pointer, Date firstDate, Date lastDate) {
        return ScoreCardUtils.calculatePointerScore(delegate, comparation, pointer, firstDate, lastDate, null);
    }

    public static List<Comparator> getComparators(DelegateBSC delegate, String mathOperation) {
        mathOperation = ScoreCardUtils.cleanOperation(mathOperation);

        List<Comparator> comparators = new ArrayList<Comparator>();
        String[] operationCrap = mathOperation.split(ScoreCardUtils.VARIABLE_EXP);

        for (String crap : operationCrap) {
            if (!"".equals(crap)) {
                mathOperation = mathOperation.replace(crap, ",");
            }
        }



        for (String comparatorVar : mathOperation.split(",")) {
            if (comparatorVar != null && !"".equals(comparatorVar) && comparatorVar.contains(ScoreCardUtils.VARIABLE_CONS) && ScoreCardUtils.isPositiveNumber(comparatorVar.replace(ScoreCardUtils.VARIABLE_CONS, ""))) {
                Long idComparator = Long.parseLong(comparatorVar.replace(ScoreCardUtils.VARIABLE_CONS, ""));
                Comparator comparator = delegate.findComparator(idComparator);
                if (comparator != null) {
                    comparators.add(comparator);
                }

            }
        }

        return comparators;
    }

    public static Score calculatePointerScore(DelegateBSC delegate, Comparation comparation, Pointer pointer, Date firstDate, Date lastDate, DimensionalCut dimensionalCut) {
        Score score = (Score) Factory.getBean("Score");

        // calculate pivot
        Comparator pivot = delegate.findComparator(pointer, comparation);
        /*
        System.out.println("Pointer: " + pointer.getDescription());
        
        System.out.println("firstDate: " + firstDate);
        System.out.println("lastDate: " + lastDate);*/

        /*
        if(dimensionalCut != null){
        System.out.println("Pivot: " + pivot.getIdComparator());
        System.out.println("DimensionalCut: " + dimensionalCut.getIdScoreCard());
        }*/

        Double pivotValue = delegate.findComparatorDimensionalCut(pivot, firstDate, lastDate, dimensionalCut);
        if (pivotValue == null) {
            score.setOutOfDate(true);
            pivotValue = 0.00D;
        }
        //CHANGE P FOR THE COMPARATORS THAT COMES FROM REQUEST OR THE GOAL OF THIS COMPARATOR
        String mathOperation = pointer.getSettings().getMathOperation(); // get math operation from scorecard settings
        // calculate comparators
        List<Comparator> comparators = ScoreCardUtils.getComparators(delegate, mathOperation);
        //System.out.println("El Math Operation es: " + mathOperation + ", " + comparators.size());
        //System.out.println("El PivotValue es: " + pivotValue);
        Double _score = ScoreCardUtils.executeOperation(delegate, comparators, score, pivotValue, firstDate, lastDate, dimensionalCut, mathOperation);
        //System.out.println("MathOperation Pointer: " + mathOperation);
        //System.out.println("El score dentro de Calculate es: " + _score);

        Settings.Polarity polarity = pointer.getSettings().getPolarity();
        if (polarity != null && (polarity == Settings.Polarity.SPECIAL || polarity == Settings.Polarity.ZERO_TREND_SPECIAL) && !_score.isNaN() && _score >= 1) {
            //System.out.println("MathOperationSpecial Pointer: " + pointer.getSettings().getSpecialOperation());
            _score = ScoreCardUtils.executeOperation(delegate, comparators, score, pivotValue, firstDate, lastDate, dimensionalCut, pointer.getSettings().getSpecialOperation());
        }

        if (_score.isNaN() || _score.isInfinite()) {
            score.setOutOfDate(true);
            //System.out.println("El indicador esta out of date");
        }
        score.setScore(comparators.size() > 0 && (_score.isNaN() || _score.isInfinite()) ? 0.0D : _score);

        return score;
    }

    private static Double executeOperation(DelegateBSC delegate, List<Comparator> comparators, Score score, Double pivotValue, Date firstDate, Date lastDate, DimensionalCut dimensionalCut, String mathOperation) {

        //System.out.println("El Math Operation es: " + mathOperation);
        //System.out.println("PivotValue: " + pivotValue);

        Expression exp = new Expression(mathOperation);
        Map<Comparator, Double> comparatorValues = ScoreCardUtils.getComparatorValue(delegate, comparators, firstDate, lastDate, dimensionalCut);
        //System.out.println("comparatorValues: "+comparatorValues.size());
        // set variables from pivot and comparators
        if (mathOperation.contains(ScoreCardUtils.VARIABLE_PIVOT)) {
            exp.setVariable(ScoreCardUtils.VARIABLE_PIVOT, pivotValue);
        }
        for (Comparator comparator : comparators) {
            //System.out.println("El comparador usado es: " + comparator.getIdComparator());
            Double comparatorValue = comparatorValues.get(comparator);
            //System.out.println("El valor del comparador es: " + comparatorValue);
            if (comparatorValue.isNaN()) {
                score.setOutOfDate(true);
            }

            //exp.setVariable(ScoreCardUtils.VARIABLE_CONS + comparator.getIdComparator(), comparatorValue.isNaN() ? 0.00D : comparatorValue);
            exp.setVariable(ScoreCardUtils.VARIABLE_CONS + comparator.getIdComparator(), comparatorValue.isNaN() ? Double.NaN : comparatorValue);

            //System.out.println(ScoreCardUtils.VARIABLE_CONS + comparator.getIdComparator()+": "+ exp.getVariable(ScoreCardUtils.VARIABLE_CONS + comparator.getIdComparator()));
        }

        return exp.resolve();
    }

    public static Map<Comparator, Double> getComparatorValue(DelegateBSC delegate, List<Comparator> comparators, Date firstDate, Date lastDate, DimensionalCut dimensionalCut) {
        Map<Comparator, Double> comparatorValues = new HashMap<Comparator, Double>();
        for (Comparator comparator : comparators) {
            Double comparatorValue = delegate.findComparatorDimensionalCut(comparator, firstDate, lastDate, dimensionalCut);
            //System.out.println("El valor del comparatorDimensionalCut es: "  + comparatorValue);
            comparatorValues.put(comparator, comparatorValue == null ? Double.NaN : comparatorValue);
        }

        return comparatorValues;
    }

    public static String cleanOperation(String mathOperation) {
        if (mathOperation.contains("(")) {
            mathOperation = mathOperation.replace("(", "");
        }
        if (mathOperation.contains(")")) {
            mathOperation = mathOperation.replace(")", "");
        }
        return mathOperation.trim();
    }

    public static boolean isPositiveNumber(String number) {
        return number.matches("([0-9])+");
    }

    public static boolean reviewRoot(List<DimensionMember> dimensionMembers) {
        boolean result = true;

        for (int j = 0; j < dimensionMembers.size(); j++) {
            DimensionMember dimensionMember = dimensionMembers.get(j);
            if (dimensionMember.getDimensionMember() != null) {
                j = dimensionMembers.size() + 1;
                result = false;
            }
        }
        return result;
    }

    public static boolean reviewRootAdvance(List<DimensionMember> dimensionMembers, List<DimensionMember> rootDimensionMembers, DimensionMember rootDimensionMember) {
        boolean result = false;
        int contador = 0;
        //System.out.println("RootDimensionMember: " + rootDimensionMember.getName());
        if (!dimensionMembers.contains(rootDimensionMember)) {
            for (int j = 0; j < dimensionMembers.size(); j++) {
                DimensionMember dimensionMember = dimensionMembers.get(j);
                //System.out.println("Miembro a evaluar: " + dimensionMember.getName());
                if (rootDimensionMembers.contains(dimensionMember)) {
                    //System.out.println("El miembro fue aceptado porque el root contiene el miembro");
                    contador++;
                } else if (dimensionMember.getDimensionMember() != null) {
                    if (dimensionMember.getDimensionMember().equals(rootDimensionMember)) {
                        //System.out.println("El miembro fue aceptado porque su padre es el rootMember");
                        contador++;
                    }
                }
            }
        }

        if (contador == dimensionMembers.size()) {
            result = true;
        }
        return result;
    }

    public static Map<DimensionMember, Boolean> reviewMembersSons(List<DimensionMember> dimensionMembers, DelegateBSC delegate) {

        Map<DimensionMember, Boolean> membersSons = new HashMap<DimensionMember, Boolean>();


        for (int j = 0; j < dimensionMembers.size(); j++) {
            DimensionMember dimensionMember = dimensionMembers.get(j);
            //System.out.println("Miembro: " + dimensionMember.getName());
            if (delegate.findDimensionMember(dimensionMember).size() == 0) {
                membersSons.put(dimensionMember, false);
            } else {
                membersSons.put(dimensionMember, true);
                //System.out.println("Tengo hijos");
            }
        }

        return membersSons;
    }

    public static List<Date> generateDates(Date date, int jump) {


        List<Date> dates = new ArrayList();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);



        int month = calendar.get(Calendar.MONTH);
        int year = calendar.get(Calendar.YEAR);

        for (int i = 0; i <= month; i = i + jump) {
            try {

                Calendar calendar2 = Calendar.getInstance();
                calendar2.set(Calendar.MONTH, i);
                //if (i == 1) {
                  /*  calendar2.add(Calendar.MONTH, -1);
                calendar2.set(Calendar.HOUR_OF_DAY, 0);
                calendar2.set(Calendar.MINUTE, 0);
                calendar2.set(Calendar.SECOND, 0);
                calendar2.set(Calendar.MILLISECOND, 0);
                calendar2.set(Calendar.DAY_OF_MONTH, 28);*/

                //} else {
                int lastDate = calendar2.getActualMaximum(Calendar.DATE);
                calendar2.set(Calendar.DATE, lastDate);
                calendar2.set(Calendar.HOUR_OF_DAY, 0);
                calendar2.set(Calendar.MINUTE, 0);
                calendar2.set(Calendar.SECOND, 0);
                calendar2.set(Calendar.MILLISECOND, 0);
                //}

                Date generatedDate = calendar2.getTime();
                dates.add(generatedDate);
                //System.out.println("La fecha generada: " + generatedDate);
            } catch (Exception e) {
            }
        }

        return dates;
    }

    public static boolean checkDate(Date date, ScoreCard scoreCard) {
        boolean result = false;

        //Generate periods using frecuency
        int jump = 1;

        switch (scoreCard.getSettings().getFrecuency()) {
            case MONTHLY:
                jump = 1;
                break;
            case BIMONTHLY:
                jump = 2;
                break;
            case QUARTERLY:
                jump = 3;
                break;
            case SEMIANNUAL:
                jump = 6;
                break;
            case ANNUAL:
                jump = 12;
                break;

        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        if ((calendar.get(Calendar.MONTH) + 1) % jump == 0) {
            result = true;
        }

        return result;
    }

    public static List<Date> generateDatesRange(HttpServletRequest request, ScoreCard scoreCard) {

        Date startDate = null;
        Date endDate = null;

        if (request.getParameter("startDate") != null && request.getParameter("endDate") != null) {
            Integer tmpDate[] = new Integer[3];
            StringTokenizer dateTokens = new StringTokenizer(request.getParameter("startDate"), "/");
            for (int i = 0; i < 3; i++) {
                tmpDate[i] = Integer.parseInt(dateTokens.nextToken());
            }

            Integer tmpDateFinal[] = new Integer[3];
            StringTokenizer dateTokensFinal = new StringTokenizer(request.getParameter("endDate"), "/");
            for (int i = 0; i < 3; i++) {
                tmpDateFinal[i] = Integer.parseInt(dateTokensFinal.nextToken());
            }

            startDate = ScoreCardUtils.generateDate(tmpDate[0], tmpDate[1], tmpDate[2]);
            endDate = ScoreCardUtils.generateDate(tmpDateFinal[0], tmpDateFinal[1], tmpDateFinal[2]);

        }

        return generateDatesRange(startDate, endDate, scoreCard);
    }

    public static List<Date> generateDatesRange(Date startDate, Date endDate, ScoreCard scoreCard) {

        //Generate periods using frecuency
        int jump = 1;

        switch (scoreCard.getSettings().getFrecuency()) {
            case MONTHLY:
                jump = 1;
                break;
            case BIMONTHLY:
                jump = 2;
                break;
            case QUARTERLY:
                jump = 3;
                break;
            case SEMIANNUAL:
                jump = 6;
                break;
            case ANNUAL:
                jump = 12;
                break;

        }

        List<Date> dates = new ArrayList();

        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);

        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endDate);



        int endMonth = endCalendar.get(Calendar.MONTH);
        int startMonth = startCalendar.get(Calendar.MONTH);

        int years = (endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR)) * 12 - (startCalendar.get(Calendar.MONTH) + 1);
        int months = endCalendar.get(Calendar.MONTH) + 1;
        int totalMonths = years + months;

        for (int i = -1; i < totalMonths; i++) {
            try {


                int lastDate = startCalendar.getActualMaximum(Calendar.DATE);
                startCalendar.set(Calendar.DATE, lastDate);
                startCalendar.set(Calendar.HOUR_OF_DAY, 0);
                startCalendar.set(Calendar.MINUTE, 0);
                startCalendar.set(Calendar.SECOND, 0);
                startCalendar.set(Calendar.MILLISECOND, 0);

                Date generatedDate = startCalendar.getTime();
                //System.out.println("Fecha Generada" + generatedDate);
                if ((startCalendar.get(Calendar.MONTH) + 1) % jump == 0) {
                    dates.add(generatedDate);
                }

                //Se regresa al minimo
                int firstDay = startCalendar.getActualMinimum(Calendar.DATE);
                startCalendar.set(Calendar.DATE, firstDay);

                startCalendar.set(Calendar.MONTH, startCalendar.get(Calendar.MONTH) + 1);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return dates;
    }

    public static List<Date> generateDatesRange(Date startDate, Date endDate) {
        List<Date> dates = new ArrayList();

        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);

        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endDate);

        int endMonth = endCalendar.get(Calendar.MONTH);
        int startMonth = startCalendar.get(Calendar.MONTH);

        int years = (endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR)) * 12 - (startCalendar.get(Calendar.MONTH) + 1);
        int months = endCalendar.get(Calendar.MONTH) + 1;
        int totalMonths = years + months;

        for (int i = -1; i < totalMonths; i++) {
            try {
                int lastDate = startCalendar.getActualMaximum(Calendar.DATE);
                startCalendar.set(Calendar.DATE, lastDate);
                startCalendar.set(Calendar.HOUR_OF_DAY, 0);
                startCalendar.set(Calendar.MINUTE, 0);
                startCalendar.set(Calendar.SECOND, 0);
                startCalendar.set(Calendar.MILLISECOND, 0);

                Date generatedDate = startCalendar.getTime();
                //System.out.println("Fecha Generada" + generatedDate);

                dates.add(generatedDate);

                //Se regresa al minimo
                int firstDay = startCalendar.getActualMinimum(Calendar.DATE);
                startCalendar.set(Calendar.DATE, firstDay);

                startCalendar.set(Calendar.MONTH, startCalendar.get(Calendar.MONTH) + 1);
            } catch (Exception e) {
            }
        }

        return dates;
    }

    public static String createMembersString(List<DimensionMember> dimensionMembers) {
        String dimensionalCutString = "";
        for (int i = 0; i < dimensionMembers.size(); i++) {
            if (i == 0) {
                dimensionalCutString += dimensionMembers.get(i).getName();
            } else {
                dimensionalCutString += "|" + dimensionMembers.get(i).getName();
            }
        }
        //System.out.println("String generado: " + dimensionalCutString);
        return dimensionalCutString;
    }

    public static Double createRandomNumber() {
        DecimalFormat format = new DecimalFormat("####.##");
        Double number = Double.parseDouble(format.format((Double) (Math.random() * 100)));
        return number;
    }

    public static Date getLastDate() {
        Date lastDate = null;
        try {
            //Variables to create Date
            DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd");
            Calendar calendar = Calendar.getInstance();
            TimeZone timeZone = calendar.getTimeZone();
            dfm.setTimeZone(timeZone);

            //Get Date of the Last Month
            int month = calendar.get(Calendar.MONTH) - 1;
            calendar.set(Calendar.MONTH, month);
            int lastDateInt = calendar.getActualMaximum(Calendar.DATE);
            calendar.set(Calendar.DATE, lastDateInt);

            //Create first date
            lastDate = calendar.getTime();

        } catch (Exception e) {
        }

        return lastDate;
    }

    public static Date getLastDate2(int monthMinus) {
        Date lastDate = null;
        try {
            //Variables to create Date
            DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd");
            Calendar calendar = Calendar.getInstance();
            TimeZone timeZone = calendar.getTimeZone();
            dfm.setTimeZone(timeZone);

            //Get Date of the Last Month
            int month = calendar.get(Calendar.MONTH) - monthMinus;
            calendar.set(Calendar.MONTH, month);
            int lastDateInt = calendar.getActualMaximum(Calendar.DATE);
            calendar.set(Calendar.DATE, lastDateInt);

            //Create first date
            lastDate = calendar.getTime();

        } catch (Exception e) {
        }

        return lastDate;
    }

    public static Date getMaximumDate(Date date) {
        Date dateResult = null;
        try {

            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            int lastDate = calendar.getActualMaximum(Calendar.DATE);
            calendar.set(Calendar.DATE, lastDate);
            calendar.set(Calendar.HOUR, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            dateResult = calendar.getTime();


        } catch (Exception e) {
        }

        return dateResult;
    }

    public static Date getMinimumDate(Date date) {
        Date dateResult = null;
        try {

            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.set(Calendar.HOUR, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            int lastDate = calendar.getActualMinimum(Calendar.DATE);
            calendar.set(Calendar.DATE, lastDate);
            dateResult = calendar.getTime();

        } catch (Exception e) {
        }

        return dateResult;
    }

    public static Date getMinimumDateMonth(int months) {
        Date date = null;
        try {

            Calendar calendar = Calendar.getInstance();

            calendar.set(Calendar.MONTH, months);
            calendar.set(Calendar.HOUR, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            int lastDate = calendar.getActualMinimum(Calendar.DATE);
            calendar.set(Calendar.DATE, lastDate);
            date = calendar.getTime();


        } catch (Exception e) {
        }

        return date;
    }
    //Returns the Date on session

    public static Date getSystemDate(HttpServletRequest request) {
        HttpSession session = request.getSession();
        Date date = (Date) session.getAttribute("date");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        return calendar.getTime();
    }

    public static Date generateDate(String date) {

        Date startDate = null;

        if (date != null) {
            Integer tmpDate[] = new Integer[3];
            StringTokenizer dateTokens = new StringTokenizer(date, "/");
            for (int i = 0; i < 3; i++) {
                tmpDate[i] = Integer.parseInt(dateTokens.nextToken());
            }

            startDate = ScoreCardUtils.generateDate(tmpDate[0], tmpDate[1], tmpDate[2]);

        }

        return startDate;
    }

    public static Date generateDate(int day, int month, int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.HOUR, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTime();

    }

    public static Date generateMinimumDate(Date date, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - month);
        calendar.set(Calendar.HOUR, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        int lastDate = calendar.getActualMinimum(Calendar.DATE);
        calendar.set(Calendar.DATE, lastDate);

        return calendar.getTime();

    }

    public static int checkFrecuency(Pointer pointer) {
        Settings settings = pointer.getSettings();
        int result = 1;

        if (settings.getFrecuency() == Settings.Frecuency.MONTHLY) {
            result = 1;
        } else if (settings.getFrecuency() == Settings.Frecuency.BIMONTHLY) {
            result = 2;
        } else if (settings.getFrecuency() == Settings.Frecuency.QUARTERLY) {
            result = 3;
        } else if (settings.getFrecuency() == Settings.Frecuency.SEMIANNUAL) {
            result = 6;
        } else if (settings.getFrecuency() == Settings.Frecuency.ANNUAL) {
            result = 12;
        }

        return result;
    }

    public static Date generateActualDate() {
        Calendar calendar = Calendar.getInstance();

        return calendar.getTime();

    }
    //Returns the Comparation on session

    public static Comparation getSystemComparation(HttpServletRequest request) {
        HttpSession session = request.getSession();
        Comparation comparation = (Comparation) session.getAttribute("comparation");
        return comparation;
    }

    public static ScoreCard getSystemScoreCardView(HttpServletRequest request) {
        HttpSession session = request.getSession();
        ScoreCard scoreCard = (ScoreCard) session.getAttribute("scoreCardView");
        return scoreCard;
    }

    public static Score calculateScore(DelegateBSC delegate, Project project) {
        Score score = (Score) Factory.getBean("Score");
        Tracer progress = delegate.findTracer(project, Tracer.Type.PROGRESS);
        Tracer budget = delegate.findTracer(project, Tracer.Type.BUDGET);
        Double budgetScore = calculateBudgetScore(delegate, project, budget);
        Double progressScore = calculateProgressScore(delegate, project, progress);

        if (budgetScore.isNaN() || progressScore.isNaN()) {
            score.setOutOfDate(true);
        }
        score.setScore(!budgetScore.isNaN() && !progressScore.isNaN() ? progress.getPercentFactor() * progressScore + budget.getPercentFactor() * budgetScore : 0.00D);

        return score;
    }

    public static Double calculateProgressScore(DelegateBSC delegate, Project project, Tracer tracer) {
        List<Milestone> milestones = delegate.findMilestone(project);
        Double score = 0.0D;
        Integer milestonesInRange = milestones.size();

        for (Milestone milestone : milestones) {
            Double milestoneScore = ScoreCardUtils.calculateMilestoneProgressScore(delegate, milestone, tracer);
            //System.out.println("El score del milestone es: "+ milestoneScore);
            if (!milestoneScore.isNaN()) {
                score += milestoneScore;
            } else {
                milestonesInRange--;
            }
        }
        //System.out.println("Los milestones en range son: " + milestonesInRange);
        return milestonesInRange > 0 ? score / milestonesInRange : 0.00D/*Double.NaN*/;
    }

    public static Double calculateBudgetScore(DelegateBSC delegate, Project project, Tracer tracer) {
        Double real = 0.0D;
        Double goal = 0.0D;

        List<Milestone> milestones = delegate.findMilestone(project);
        for (Milestone milestone : milestones) {
            MilestoneTracer milestoneTracer = delegate.findMilestoneTracer(milestone, tracer);
            Double milestoneTracerReal = milestoneTracer.getRealValue();
            Double milestoneTracerGoal = milestoneTracer.getGoalValue();
            if (milestoneTracerReal != null && milestoneTracerGoal != null) {
                real += milestoneTracer.getRealValue();
                goal += milestoneTracer.getGoalValue();
            }
        }

        return real != 0 ? goal / real : 0.00D/*Double.NaN*/;

    }

    public static Double calculateBudgetScoreMilestone(DelegateBSC delegate, MilestoneTracer milestoneTracer) {
        Double score = 0.0D;

        Double milestoneTracerReal = milestoneTracer.getRealValue();
        Double milestoneTracerGoal = milestoneTracer.getGoalValue();

        if (milestoneTracerReal != null && milestoneTracerGoal != null) {
            score = milestoneTracerGoal / milestoneTracerReal;
        }

        return score;
    }

    public static Double calculateMilestoneProgressScore(DelegateBSC delegate, Milestone milestone, Tracer tracer) {
        MilestoneTracer milestoneTracer = delegate.findMilestoneTracer(milestone, tracer);
        Double goal = ScoreCardUtils.getProgressGoal(milestone);
        Double real = milestoneTracer.getRealValue();
        //System.out.println("Goal Milestone Progress: " + goal);

        return (goal != null && goal != 0) && real != null ? real / goal : Double.NaN;
    }

    public static Double getProgressGoal(Milestone milestone) {
        Date firstDate = milestone.getBeginDate();
        Date today = Calendar.getInstance().getTime();

        if (today.before(firstDate)) {
            return null;
        }

        Date lastDate = milestone.getEndDate();
        if (lastDate.before(today)) {
            today = lastDate;
        }

        Integer milestoneDays = ScoreCardUtils.getWorkingDays(firstDate, lastDate);
        Integer rangeDays = ScoreCardUtils.getWorkingDays(firstDate, today);

        return (double) rangeDays / milestoneDays;
    }

    public static Double getRealProgress(DelegateBSC delegate, Project project, Tracer tracer) {
        List<Milestone> milestones = delegate.findMilestone(project);
        int projectTotalDays = ScoreCardUtils.getWorkingDays(delegate, project);
        double realProgress = 0;

        for (Milestone milestone : milestones) {
            MilestoneTracer milestoneTracer = delegate.findMilestoneTracer(milestone, tracer);
            if (milestoneTracer.getRealValue() == null) {
                continue;
            }

            int milestoneDays = ScoreCardUtils.getWorkingDays(milestone.getBeginDate(), milestone.getEndDate());
            double milestonePercent = milestoneDays / projectTotalDays;
            realProgress += milestoneTracer.getRealValue() * milestonePercent;
        }

        return realProgress;
    }

    public static Double getRealProgress(DelegateBSC delegate, int projectTotalDays, Task task, Tracer tracer) {
        List<Task> tasks = delegate.findTask(task);
        if (task instanceof Milestone) {
            Milestone milestone = (Milestone) task;
            MilestoneTracer milestoneTracer = delegate.findMilestoneTracer(milestone, tracer);
            int milestoneDays = ScoreCardUtils.getWorkingDays(milestone.getBeginDate(), milestone.getEndDate());

            double milestonePercent = (double) milestoneDays / projectTotalDays;

            return milestoneTracer.getRealValue() == null ? 0 : milestoneTracer.getRealValue() * milestonePercent;
        } else {
            double realProgress = 0;
            for (Task taskChild : tasks) {
                realProgress += ScoreCardUtils.getRealProgress(delegate, projectTotalDays, taskChild, tracer);


            }
            return realProgress;
        }
    }

    public static Double getGoalProgress(DelegateBSC delegate, int projectTotalDays, Task task, Tracer tracer) {
        List<Task> tasks = delegate.findTask(task);
        if (tasks.isEmpty() && task instanceof Milestone) {
            Milestone milestone = (Milestone) task;
            MilestoneTracer milestoneTracer = delegate.findMilestoneTracer(milestone, tracer);
            int milestoneDays = ScoreCardUtils.getWorkingDays(milestone.getBeginDate(), milestone.getEndDate());

            double milestonePercent = (double) milestoneDays / projectTotalDays;

            return (getProgressGoal(milestone) != null) ? getProgressGoal(milestone) * milestonePercent : 0.00D;
        } else {
            double goalProgress = 0;
            for (Task taskChild : tasks) {
                goalProgress += ScoreCardUtils.getGoalProgress(delegate, projectTotalDays, taskChild, tracer);
            }
            return goalProgress;
        }
    }

    public static int getWorkingDays(DelegateBSC delegate, Project project) {
        List<Milestone> milestones = delegate.findMilestone(project);
        int milestoneDays = 0;

        for (Milestone milestone : milestones) {
            milestoneDays += ScoreCardUtils.getWorkingDays(milestone.getBeginDate(), milestone.getEndDate());
        }

        return milestoneDays;
    }

    public static int getWorkingDays(Date startDate, Date endDate) {
        Calendar startCal;
        Calendar endCal;
        startCal = Calendar.getInstance();
        startCal.setTime(startDate);
        endCal = Calendar.getInstance();
        endCal.setTime(endDate);
        int workDays = 0;

        //Return 1 if start and end are the same
        if (startCal.getTimeInMillis() == endCal.getTimeInMillis()) {
            return 1;
        }

        if (startCal.getTimeInMillis() > endCal.getTimeInMillis()) {
            startCal.setTime(endDate);
            endCal.setTime(startDate);
        }

        do {
            startCal.add(Calendar.DAY_OF_MONTH, 1);
            if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
                ++workDays;
            }

        } while (startCal.getTimeInMillis() < endCal.getTimeInMillis());

        return workDays;
    }

    public static String getURIParams(HttpServletRequest request) {
        String uriParams = "?";
        Enumeration parameters = request.getParameterNames();
        List<String> params = new ArrayList<String>();
        while (parameters.hasMoreElements()) {
            String param = parameters.nextElement().toString();
            params.add(param + "=" + request.getParameter(param));
        }
        for (int i = params.size() - 1; i >= 0; i--) {
            String param = params.get(i);
            //uriParams += count == 0 ? param+"="+request.getParameter(param) : "%26"+param+"="+request.getParameter(param);
            uriParams += i == params.size() - 1 ? param : "%26" + param;
        }
        return uriParams;
    }

    public static List<List<DimensionMember>> getCrossProduct(DelegateBSC delegate, List<Dimension> dimensions) {
        if (dimensions == null || dimensions.isEmpty()) {
            return ListUtils.EMPTY_LIST;
        }

        Dimension dimensionPivot = dimensions.remove(0);
        int dimensionPosition = 0;
        List<List<DimensionMember>> dimensionDimensionalMembers = ScoreCardUtils.getDimensionMemberMatrix(delegate, dimensions);
        List<List<DimensionMember>> crossProduct = new ArrayList<List<DimensionMember>>();
        List<DimensionMember> pivotMembers = delegate.findDimensionMember(dimensionPivot);
        for (DimensionMember pivotMember : pivotMembers) {
            for (List<DimensionMember> combination : ScoreCardUtils.getCrossProduct(pivotMember, dimensionDimensionalMembers, dimensionPosition)) {
                crossProduct.add(combination);
            }
        }
        return crossProduct;
    }

    private static List<List<DimensionMember>> getDimensionMemberMatrix(DelegateBSC delegate, List<Dimension> dimensions) {
        List<List<DimensionMember>> dimensionDimensionalMembers = new ArrayList<List<DimensionMember>>();
        for (Dimension dimension : dimensions) {
            List<DimensionMember> dimensionMembers = delegate.findDimensionMember(dimension);
            dimensionDimensionalMembers.add(dimensionMembers);
        }
        return dimensionDimensionalMembers;
    }

    private static List<List<DimensionMember>> getCrossProduct(DimensionMember pivot, List<List<DimensionMember>> dimensionDimensionalMembers, int dimensionPosition) {
        List<DimensionMember> dimensionMembers = dimensionPosition > dimensionDimensionalMembers.size() - 1 ? null : (List<DimensionMember>) dimensionDimensionalMembers.get(dimensionPosition);
        if (dimensionMembers == null) {
            List<List<DimensionMember>> crossElements = new ArrayList<List<DimensionMember>>();
            List<DimensionMember> combination = new ArrayList<DimensionMember>();
            combination.add(pivot);
            crossElements.add(combination);
            return crossElements;
        } else {
            List<List<DimensionMember>> crossElements = new ArrayList<List<DimensionMember>>();
            dimensionPosition++;
            for (DimensionMember dimensionMember : dimensionMembers) {
                for (List<DimensionMember> combination : ScoreCardUtils.getCrossProduct(dimensionMember, dimensionDimensionalMembers, dimensionPosition)) {
                    combination.add(pivot);
                    crossElements.add(combination);
                }
            }

            return crossElements;
        }
    }

    public static List<ScoreCard> getScoreCards(DelegateBSC delegate, ScoreCard root) {
        List<ScoreCard> scoreChildren = delegate.findScoreCard(root);// children scorecards
        if (scoreChildren.isEmpty()) {
            List<ScoreCard> scoreCards = new ArrayList<ScoreCard>();
            scoreCards.add(root);
            return scoreCards;
        } else {
            List<ScoreCard> scoreCards = new ArrayList<ScoreCard>();
            scoreCards.add(root);
            for (ScoreCard scoreCard : scoreChildren) {
                scoreCards = ListUtils.union(scoreCards, ScoreCardUtils.getScoreCards(delegate, scoreCard));
            }
            return scoreCards;
        }
    }

    public static List<Project> getProjectScoreCards(DelegateBSC delegate, ScoreCard root) {
        List<ScoreCard> scoreCards = ScoreCardUtils.getScoreCards(delegate, root);
        List<Project> projectScoreCards = new ArrayList<Project>();
        for (ScoreCard scoreCard : scoreCards) {
            if (scoreCard instanceof Project) {
                projectScoreCards.add((Project) scoreCard);
            }
        }

        return projectScoreCards;
    }

    public static List<TracerPojo> getProjectTracer(DelegateBSC delegate, Project project) {
        //Get the tracers (Budget - Progress) of the project
        List<Tracer> tracersProject = delegate.findTracer(project);

        //Create the tracersPojo with the information about Tracers.
        List<TracerPojo> tracersPojo = new ArrayList<TracerPojo>();

        //Se agrega el tracer TOTAL

        TracerPojo tracerPojo = new TracerPojo();
        tracerPojo.setName("Total");
        tracerPojo.setWeight(1D);
        tracerPojo.setScore(ScoreCardUtils.calculateScore(delegate, project).getScore());

        //Color
        Colorimetry colorimetry = delegate.findColorimetry(project, tracerPojo.getScore());
        String color = "FFFFFF";

        tracerPojo.setColor(colorimetry.getColor());

        tracersPojo.add(tracerPojo);

        Tracer tracerBudget = null;
        Tracer tracerProgress = null;

        //Fill the tracerPojo with the info.
        for (Tracer tracer : tracersProject) {
            TracerPojo tracerPojoI = new TracerPojo();
            tracerPojoI.setName(tracer.getName());
            tracerPojoI.setWeight(tracer.getPercentFactor());
            if (tracer.getType() == Tracer.Type.PROGRESS) {
                tracerPojoI.setScore(ScoreCardUtils.calculateProgressScore(delegate, project, tracer));
                tracerProgress = tracer;
            } else if (tracer.getType() == Tracer.Type.BUDGET) {
                tracerPojoI.setScore(ScoreCardUtils.calculateBudgetScore(delegate, project, tracer));
                tracerBudget = tracer;
            }
            //Color
            Colorimetry colorimetryI = delegate.findColorimetry(project, tracerPojoI.getScore());
            tracerPojoI.setColor(colorimetryI.getColor());
            tracersPojo.add(tracerPojoI);
        }

        return tracersPojo;
    }

    public static List<DimensionalCut> getDimensionalCuts(DelegateBSC delegate, DimensionalCut dimensionalCutRoot) {
        //Find the cuts of the pointer
        List<DimensionalCut> dimensionalCuts = delegate.findDimensionalCut(dimensionalCutRoot.getPointer());
        //System.out.println("El indicador tiene: " + dimensionalCuts.size());
        List<DimensionalCut> rootDimensionalCuts = new ArrayList<DimensionalCut>();

        List<DimensionMember> rootDimensionMembers = delegate.findDimensionMember(dimensionalCutRoot);

        for (DimensionalCut dimensionalCut : dimensionalCuts) {
            List<DimensionMember> dimensionMembers = delegate.findDimensionMember(dimensionalCut);

            for (DimensionMember rootDimensionMember : rootDimensionMembers) {
                if (ScoreCardUtils.reviewRootAdvance(dimensionMembers, rootDimensionMembers, rootDimensionMember)) {
                    //System.out.println("Acepte el corte: " + dimensionalCut.getName());
                    //System.out.println("Miembro: " + rootDimensionMember.getName());
                    rootDimensionalCuts.add(dimensionalCut);
                }
            }

        }
        return rootDimensionalCuts;
    }

    public static List<DimensionalCut> getDrillDimensionalCuts(DelegateBSC delegate, DimensionalCut dimensionalCutRoot) {
        //Find the cuts of the pointer
        List<DimensionalCut> dimensionalCuts = delegate.findDimensionalCut(dimensionalCutRoot.getPointer());
        //System.out.println("El indicador tiene: " + dimensionalCuts.size());
        List<DimensionalCut> rootDimensionalCuts = new ArrayList<DimensionalCut>();

        rootDimensionalCuts.add(dimensionalCutRoot);

        List<DimensionMember> rootDimensionMembers = delegate.findDimensionMember(dimensionalCutRoot);

        for (DimensionalCut dimensionalCut : dimensionalCuts) {
            List<DimensionMember> dimensionMembers = delegate.findDimensionMember(dimensionalCut);

            for (DimensionMember rootDimensionMember : rootDimensionMembers) {
                if (ScoreCardUtils.reviewRootAdvance(dimensionMembers, rootDimensionMembers, rootDimensionMember)) {
                    //System.out.println("Acepte el corte: " + dimensionalCut.getName());
                    //System.out.println("Miembro: " + rootDimensionMember.getName());
                    rootDimensionalCuts.add(dimensionalCut);
                    rootDimensionalCuts = ListUtils.union(rootDimensionalCuts, ScoreCardUtils.getDrillDimensionalCuts(delegate, dimensionalCut));

                }
            }

        }
        return rootDimensionalCuts;
    }

    public static List<DimensionalCut> getDimensionalCutScoreCards(DelegateBSC delegate, ScoreCard root) {
        List<DimensionalCut> dimensionalCutScoreCards = new ArrayList();
        List<ScoreCard> rootScoreCards = ScoreCardUtils.getScoreCards(delegate, root);
        Collections.sort(rootScoreCards);
        for (ScoreCard scoreCard : rootScoreCards) {
            if (scoreCard instanceof DimensionalCut) {
                dimensionalCutScoreCards.add((DimensionalCut) scoreCard);
            }
        }

        return dimensionalCutScoreCards;
    }

    public static List<DimensionalCut> getAllDimensionalCutScoreCards(DelegateBSC delegate, ScoreCard root) {
        List<DimensionalCut> dimensionalCutScoreCards = new ArrayList();
        List<DimensionalCut> finalDimensionalCutScoreCards = new ArrayList();

        List<ScoreCard> rootScoreCards = ScoreCardUtils.getScoreCards(delegate, root);
        Collections.sort(rootScoreCards);
        for (ScoreCard scoreCard : rootScoreCards) {
            if (scoreCard instanceof DimensionalCut) {
                dimensionalCutScoreCards.add((DimensionalCut) scoreCard);
            }
        }

        for (DimensionalCut dimensionalCut : dimensionalCutScoreCards) {
            List<DimensionalCut> drillList = ScoreCardUtils.getDrillDimensionalCuts(delegate, dimensionalCut);
            finalDimensionalCutScoreCards = ListUtils.union(finalDimensionalCutScoreCards, drillList);
        }

        return finalDimensionalCutScoreCards;
    }

    public static List<DimensionalCut> hasPointerRelation(DelegateBSC delegate, Pointer pointer) {

        List<DimensionalCut> dimensionalCuts = delegate.findDimensionalCut(pointer);
        List<DimensionalCut> resultDimensionalCuts = new ArrayList<DimensionalCut>();

        for (DimensionalCut dimensionalCut : dimensionalCuts) {
            if (ScoreCardUtils.hasScoreCardRelation(delegate, dimensionalCut)) {
                resultDimensionalCuts.add(dimensionalCut);
            }
        }

        return resultDimensionalCuts;
    }

    public static boolean hasScoreCardRelation(DelegateBSC delegate, ScoreCard scoreCard) {
        // Check if the scorecard has sons
        List<ScoreCard> scoreCardSons = delegate.findOtherScoreCards(scoreCard.getIdScoreCard());
        // Check if the scorecard has daddys
        List<ScoreCard> scoreCardFathers = delegate.findOtherScoreCardsRevert(scoreCard.getIdScoreCard());

        return scoreCardSons.size() != 0 || scoreCardFathers.size() != 0;
    }

    public static boolean deleteScoreCard(HttpServletRequest request, HttpServletResponse response, DelegateBSC delegate, ScoreCard scoreCard) {


        if (scoreCard == null || ScoreCardUtils.hasScoreCardRelation(delegate, scoreCard) || scoreCard.getScoreview() != null) {
            return false;
        }

        List<PersonScoreCard> personScoreCards = delegate.findPersonScoreCard(scoreCard);
        for (PersonScoreCard personScoreCard : personScoreCards) {
            delegate.deletePersonScoreCard(personScoreCard);
        }

        //Delete ActionPlan
        ScoreCardUtils.deleteScoreCardActionPlans(delegate, scoreCard);


        //Delete Notes
        ScoreCardUtils.deleteScoreCardNotes(delegate, scoreCard);
        /*List<Note> notes = delegate.findNote(scoreCard);
        for (Note note : notes) {
        DeleteNote.processRequestInternal(request, response, delegate, note);
         */

        //Delete topics
        ScoreCardUtils.deleteScoreCardTopics(delegate, scoreCard);

        //Delete settings
        Settings settings = scoreCard.getSettings();
        if (settings != null) {
            scoreCard.setSettings(null);
            delegate.updateScoreCard(scoreCard);

            settings.setScoreCard(null);
            delegate.updateSettings(settings);

            List<ColorimetrySettings> colorimetrySettings = delegate.findColorimetrySettings(settings);
            for (ColorimetrySettings colorimetrySetting : colorimetrySettings) {
                delegate.deleteColorimetrySettings(colorimetrySetting);
            }

            if (scoreCard instanceof bsc.ejb.entity.Map) {
                bsc.ejb.entity.Map map = (bsc.ejb.entity.Map) scoreCard;
                if (map.getMapDrawing() != null) {
                    MapDrawing mapDrawing = map.getMapDrawing();
                    mapDrawing.setMap(null);
                    delegate.updateMapDrawing(mapDrawing);

                    map.setMapDrawing(null);
                    delegate.updateMap(map);
                }

                List<MapDrawingSettings> mapDrawingSettings = delegate.findMapDrawingSettings(settings);
                for (MapDrawingSettings mapDrawingSetting : mapDrawingSettings) {
                    delegate.deleteMapDrawingSettings(mapDrawingSetting);
                }
            }
            delegate.deleteSettings(settings);
        }

        if (scoreCard instanceof Pointer) {
            List<DimensionalCut> dimensionalCuts = delegate.findDimensionalCut((Pointer) scoreCard);
            for (DimensionalCut dimensionalCut : dimensionalCuts) {
                List<ComparatorDimensionalCut> comparatorDimensionalCuts = delegate.findComparatorDimensionalCut(dimensionalCut);
                for (ComparatorDimensionalCut comparatorDimensionalCut : comparatorDimensionalCuts) {
                    delegate.deleteComparatorDimensionalCut(comparatorDimensionalCut);
                }

                List<Comparator> comparators = delegate.findComparator(dimensionalCut);
                for (Comparator comparator : comparators) {
                    Settings comparatorSettings = comparator.getSettings();

                    comparator.setSettings(null);
                    comparatorSettings.setComparator(null);

                    delegate.updateComparator(comparator);
                    delegate.updateSettings(comparatorSettings);

                    delegate.deleteSettings(comparatorSettings);
                    delegate.deleteComparator(comparator);
                }

                List<DimensionalCutMember> dimensionalCutMembers = delegate.findDimensionalCutMember(dimensionalCut);
                for (DimensionalCutMember dimensionalCutMember : dimensionalCutMembers) {
                    delegate.deleteDimensionalCutMember(dimensionalCutMember);
                }

                //delegate.deleteDimensionalCut(dimensionalCut);
                ScoreCardUtils.deleteDimensionalCut(delegate, dimensionalCut);
            }

            List<Comparator> comparators = delegate.findComparator((Pointer) scoreCard);
            for (Comparator comparator : comparators) {
                Settings comparatorSettings = comparator.getSettings();

                comparator.setSettings(null);
                comparatorSettings.setComparator(null);

                delegate.updateComparator(comparator);
                delegate.updateSettings(comparatorSettings);

                delegate.deleteSettings(comparatorSettings);
                delegate.deleteComparator(comparator);
            }

            List<ScoreCardDimension> scoreCardDimensions = delegate.findScoreCardDimension(scoreCard);
            for (ScoreCardDimension scoreCardDimension : scoreCardDimensions) {
                delegate.deleteScoreCardDimension(scoreCardDimension);
            }
        }

        if (scoreCard instanceof Project) {
            List<Milestone> milestones = delegate.findMilestone((Project) scoreCard);
            for (Milestone milestone : milestones) {

                List<MilestoneTracer> milestoneTracers = delegate.findMilestoneTracer(milestone);
                for (MilestoneTracer milestoneTracer : milestoneTracers) {
                    delegate.deleteMilestoneTracer(milestoneTracer);
                }

                milestone.setTask(null);
                milestone.setTask(null);
                milestone.setTasks(null);
                milestone.setProject(null);
                delegate.updateMilestone(milestone);
            }

            for (Milestone milestone : milestones) {
                delegate.deleteMilestone(milestone);
            }

            List<Tracer> tracers = delegate.findTracer((Project) scoreCard);
            for (Tracer tracer : tracers) {
                delegate.deleteTracer(tracer);
            }

            List<Label> labels = delegate.findLabel((Project) scoreCard);
            for (Label label : labels) {
                label.setTask(null);
                label.setTasks(null);
                label.setProject(null);
                delegate.updateLabel(label);
            }
            for (Label label : labels) {
                delegate.deleteLabel(label);
            }

            // List<ScoreCardRelation> scoreCardRelation = delegate.findScoreCardR
        }

        //FALTA BORRAR SCORECARD, MAPA, INDICADOR Y PROYECTOS

        delegate.deleteScoreCard(scoreCard);
        return true;
    }

    public static boolean hasData(DelegateBSC delegate, ScoreCard scoreCard, Comparator comparator, Date date) {
        boolean result = true;

        List<DimensionalCut> dimensionalCuts = delegate.findDimensionalCut((Pointer) scoreCard);
        for (DimensionalCut dimensionalCut : dimensionalCuts) {
            ComparatorDimensionalCut comparatorDimensionalCut = delegate.findComparatorDimensionalCut(comparator, dimensionalCut, date);
            if (comparatorDimensionalCut == null) {
                return false;
            }
        }

        return result;
    }

    //VISION 1.5
    //List of members of each cut
    public static Map<DimensionalCut, List<DimensionMember>> getDimensionalCutsMembers(HttpServletRequest request, DelegateBSC delegate, List<DimensionalCut> dimensionalCuts) {
        //Se buscan los miembros de cada de lo Cut-Pointers
        Map<DimensionalCut, List<DimensionMember>> dimensionalCutsMembers = new HashMap<DimensionalCut, List<DimensionMember>>();
        for (DimensionalCut dimensionalCut : dimensionalCuts) {
            List<DimensionMember> dimensionMembers = delegate.findDimensionMember(dimensionalCut);
            dimensionalCutsMembers.put(dimensionalCut, dimensionMembers);
        }


        return dimensionalCutsMembers;
    }

    //List of members (String) of each cut
    public static Map<DimensionalCut, String> getDimensionalCutsMembersStrings(HttpServletRequest request, DelegateBSC delegate, List<DimensionalCut> dimensionalCuts) {
        //Se buscan los miembros de cada de lo Cut-Pointers
        Map<DimensionalCut, String> dimensionalCutsMembers = new HashMap<DimensionalCut, String>();

        for (DimensionalCut dimensionalCut : dimensionalCuts) {
            List<DimensionMember> dimensionMembers = delegate.findDimensionMember(dimensionalCut);
            String dimensionMembersString = ScoreCardUtils.createMembersString(dimensionMembers);
            dimensionalCutsMembers.put(dimensionalCut, dimensionMembersString);
        }

        return dimensionalCutsMembers;
    }

    //List of scorecards without Pointer-Templates
    public static List<ScoreCard> getAllScoreCards(HttpServletRequest request, DelegateBSC delegate) {

        List<Pointer> pointers = new ArrayList<Pointer>();
        List<DimensionalCut> dimensionalCuts = new ArrayList<DimensionalCut>();

        List<ScoreCard> allScoreCards = delegate.findScoreCard();
        //Se quita de la lista los templates
        for (ScoreCard scoreCard : allScoreCards) {
            if (scoreCard instanceof Pointer) {
                pointers.add((Pointer) scoreCard);
            }
            if (scoreCard instanceof DimensionalCut) {
                dimensionalCuts.add((DimensionalCut) scoreCard);
            }
        }

        //Se limpia la lista de pointers
        pointers = ListUtils.subtract(pointers, dimensionalCuts);
        allScoreCards = ListUtils.subtract(allScoreCards, pointers);

        return allScoreCards;
    }

    //List of DimensionalCuts
    public static List<DimensionalCut> getDimensionalCuts(HttpServletRequest request, DelegateBSC delegate) {


        List<DimensionalCut> dimensionalCuts = new ArrayList<DimensionalCut>();

        List<ScoreCard> allScoreCards = delegate.findScoreCard();
        //Se quita de la lista los templates
        for (ScoreCard scoreCard : allScoreCards) {
            if (scoreCard instanceof DimensionalCut) {
                dimensionalCuts.add((DimensionalCut) scoreCard);
            }
        }

        return dimensionalCuts;
    }

    //Get Action Plans
    public static List<ActionPlanPojo> getActionPlans(DelegateBSC delegate, ScoreCard scoreCard) {
        //Se obtienen los planes de acción
        List<ActionPlan> actionPlans = delegate.findActionPlan(scoreCard);
        //Pojos de los planes de acción
        List<ActionPlanPojo> actionPlanPojos = new ArrayList<ActionPlanPojo>();
        //se buscan los responsables y attachments
        for (ActionPlan actionPlan : actionPlans) {

            /*Person responsible = delegate.findActionPlanPerson(actionPlan, ActionPlanPerson.Profile.RESPONSIBLE).getPerson();
            Person author = delegate.findActionPlanPerson(actionPlan, ActionPlanPerson.Profile.AUTHOR).getPerson();

            ActionPlanPojo actionPlanPojo = (ActionPlanPojo) Factory.getBean("ActionPlanPojo");
            actionPlanPojo.setActionPlan(actionPlan);
            actionPlanPojo.setResponsible(responsible);
            actionPlanPojo.setAuthor(author);
            actionPlanPojo.setAttachments(delegate.findAttachment(actionPlan));*/

            actionPlanPojos.add(ScoreCardUtils.getActionPlan(delegate, actionPlan));
        }
        return actionPlanPojos;
    }

    //Get Action Plans
    public static ActionPlanPojo getActionPlan(DelegateBSC delegate, ActionPlan actionPlan) {

        Person responsible = delegate.findActionPlanPerson(actionPlan, ActionPlanPerson.Profile.RESPONSIBLE).getPerson();
        Person author = delegate.findActionPlanPerson(actionPlan, ActionPlanPerson.Profile.AUTHOR).getPerson();

        ActionPlanPojo actionPlanPojo = (ActionPlanPojo) Factory.getBean("ActionPlanPojo");
        actionPlanPojo.setActionPlan(actionPlan);
        actionPlanPojo.setResponsible(responsible);
        actionPlanPojo.setAuthor(author);
        actionPlanPojo.setAttachments(delegate.findAttachment(actionPlan));

        return actionPlanPojo;
    }

    //Delete ActionPlans
    public static void deleteScoreCardActionPlans(DelegateBSC delegate, ScoreCard scoreCard) {

        //Se obtienen los planes de acción
        List<ActionPlan> actionPlans = delegate.findActionPlan(scoreCard);
        for (ActionPlan actionPlan : actionPlans) {
            ScoreCardUtils.deleteActionPlan(delegate, actionPlan);
        }

    }

    public static void deleteActionPlan(DelegateBSC delegate, ActionPlan actionPlan) {
        List<Attachment> attachments = delegate.findAttachment(actionPlan);
        for (Attachment attachment : attachments) {
            try {
                FileUtils.forceDelete(new File(attachment.getAttachment()));
            } catch (Exception e) {
                e.printStackTrace();
            }
            delegate.deleteAttachment(attachment);
        }

        ActionPlanPerson actionPlanPersonAuthor = delegate.findActionPlanPerson(actionPlan, ActionPlanPerson.Profile.AUTHOR);
        ActionPlanPerson actionPlanPersonResponsible = delegate.findActionPlanPerson(actionPlan, ActionPlanPerson.Profile.RESPONSIBLE);

        delegate.deleteActionPlanPerson(actionPlanPersonAuthor);
        delegate.deleteActionPlanPerson(actionPlanPersonResponsible);

        delegate.deleteActionPlan(actionPlan);
    }

    public static void deleteScoreCardNotes(DelegateBSC delegate, ScoreCard scoreCard) {
        List<Note> notes = delegate.findNote(scoreCard);
        for (Note note : notes) {
            ScoreCardUtils.deleteNote(delegate, note);
        }
    }

    public static void deleteNote(DelegateBSC delegate, Note note) {
        List<Attachment> attachments = delegate.findAttachment(note);
        for (Attachment attachment : attachments) {
            try {
                FileUtils.forceDelete(new File(attachment.getAttachment()));
            } catch (Exception e) {
                e.printStackTrace();
            }
            delegate.deleteAttachment(attachment);
        }
        delegate.deleteNote(note);
    }

    public static void deleteScoreCardTopics(DelegateBSC delegate, ScoreCard scoreCard) {
        List<Topic> topics = delegate.findTopic(scoreCard);
        for (Topic topic : topics) {
            ScoreCardUtils.deleteTopic(delegate, topic);
        }
    }

    public static void deleteTopic(DelegateBSC delegate, Topic topic) {
        List<TopicScoreView> topicScoreViews = delegate.findTopicScoreView(topic);
        for (TopicScoreView topicScoreView : topicScoreViews) {
            delegate.deleteTopicScoreView(topicScoreView);
        }

        List<SRMTopic> SRMTopics = delegate.findSRMTopic(topic);
        for (SRMTopic sRMTopic : SRMTopics) {
            delegate.deleteSRMTopic(sRMTopic);
        }
        delegate.deleteTopic(topic);
    }

    public static void deleteDimensionalCut(DelegateBSC delegate, DimensionalCut dimensionalCut) {

        ScoreCardUtils.deleteScoreCardActionPlans(delegate, dimensionalCut);
        ScoreCardUtils.deleteScoreCardNotes(delegate, dimensionalCut);
        ScoreCardUtils.deleteScoreCardTopics(delegate, dimensionalCut);
        delegate.deleteDimensionalCut(dimensionalCut);
    }
}
